package com.apobates.jforum2.troll.accounts.biz.impl.dao;

import com.apobates.jforum2.troll.accounts.biz.dao.MemberOnlineDao;
import com.apobates.jforum2.troll.accounts.entity.MemberOnline;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 *
 * @author xiaofanku
 * @since 20200515
 */
@Repository
public class MemberOnlineDaoImpl implements MemberOnlineDao{
    @PersistenceContext
    private EntityManager entityManager;
    @Value("${spring.jpa.batch.size}")
    private int batchSize;
    private final static Logger logger = LoggerFactory.getLogger(MemberOnlineDaoImpl.class);
    
    @Override
    public Stream<MemberOnline> findAll(List<Long> memberIdList) {
        if (memberIdList == null || memberIdList.isEmpty()) {
            return Stream.empty();
        }
        return entityManager.createQuery("SELECT mo FROM MemberOnline mo WHERE mo.mid IN ?1", MemberOnline.class).setParameter(1, memberIdList).getResultStream();
    }
    
    @Override
    public Stream<MemberOnline> findAll(LocalDateTime start, LocalDateTime finish) {
        return entityManager.createQuery("SELECT mo FROM MemberOnline mo WHERE mo.activeDateTime BETWEEN ?1 AND ?2 ORDER BY mo.activeDateTime DESC", MemberOnline.class)
                .setParameter(1, start)
                .setParameter(2, finish)
                .getResultStream();
    }
    
    @Override
    public long countByDateTime(LocalDateTime start, LocalDateTime finish) {
        try {
            return entityManager.createQuery("SELECT COUNT(mo) FROM MemberOnline mo WHERE mo.activeDateTime BETWEEN ?1 AND ?2", Long.class)
                    .setParameter(1, start)
                    .setParameter(2, finish)
                    .getSingleResult();
        } catch (Exception e) {
            if (logger.isDebugEnabled()) {
                logger.debug("[countByDateTime][MemberOnlineDao]", e);
            }
        }
        return 0L;
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public int batchSave(List<MemberOnline> entities) {
        int i = 0;
        for (MemberOnline mo : entities) {
            entityManager.persist(mo);
            i++;
            if (i % batchSize == 0) {
                // Flush a batch of inserts and release memory.
                entityManager.flush();
                entityManager.clear();
            }
        }
        return i;
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void save(MemberOnline entity) {
        entityManager.persist(entity);
    }
    
    @Override
    public Optional<MemberOnline> findOne(String primaryKey) {
        return Optional.ofNullable(entityManager.find(MemberOnline.class, primaryKey));
    }
    
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Optional<Boolean> edit(MemberOnline updateEntity) {
        try {
            entityManager.merge(updateEntity);
            return Optional.of(true);
        } catch (Exception e) {
            if(logger.isDebugEnabled()){
                logger.debug(e.getMessage(), e);
            }
            return Optional.empty(); //.failure(e);
        }
    }
    
    @Override
    public Stream<MemberOnline> findAll() {
        return entityManager.createQuery("SELECT mo FROM MemberOnline mo", MemberOnline.class).getResultStream();
    }
    
    @Override
    public long count() {
        try {
            return entityManager.createQuery("SELECT COUNT(mo) FROM MemberOnline mo", Long.class).getSingleResult();
        } catch (Exception e) {
            if (logger.isDebugEnabled()) {
                logger.debug("[count][MemberOnlineDao]", e);
            }
        }
        return 0L;
    }
    
    @Override
    public Optional<MemberOnline> findOneByMember(long memberId) {
        try{
            MemberOnline mo = entityManager.createQuery("SELECT mo FROM MemberOnline mo WHERE mo.mid > 0 AND mo.mid = ?1 ORDER BY mo.activeDateTime DESC", MemberOnline.class).setParameter(1, memberId).setMaxResults(1).getSingleResult();
            return Optional.ofNullable(mo);
        }catch(javax.persistence.NoResultException e){
            if(logger.isDebugEnabled()){
                logger.debug("查看非游客的在线记录失败", e);
            }
        }
        return Optional.empty();
    }
    /**
     * [NativeSQL]
     * @return 
     */
    @Override
    @SuppressWarnings("unchecked")
    public Stream<MemberOnline> findDuplicateRecords() {
        final String SQL="SELECT t1.* FROM apo_member_online AS t1 WHERE EXISTS (SELECT 1 FROM apo_member_online AS t2 WHERE t2.MID = t1.MID and t2.ACTIVEDATETIME > t1.ACTIVEDATETIME)";
        return entityManager.createNativeQuery(SQL, MemberOnline.class).getResultStream();
    }
    /**
     * [NativeSQL]
     * @return 
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public int deleteDuplicateRecords() {
        final String SQL="DELETE FROM t1 FROM `apo_member_online` AS t1 , `apo_member_online` AS t2 WHERE t2.MID = t1.MID AND t2.ACTIVEDATETIME > t1.ACTIVEDATETIME";
        return entityManager.createNativeQuery(SQL).executeUpdate();
    }
}